﻿Function.RegisterNamespace("Test.xUnit.js");

[Import("../../Source/xUnit.js/Stubs.js")]
[Fixture]
Test.xUnit.js.Stubs=function(){
    [Fixture]
    function GetList(){
        [Fact]
        function ThrowsIfSourceListIsNull(){
            var expected="xUnit.js.Stubs.GetList: 'sourceList' must be a valid Array.";

            var actual=Record.Exception(function(){
                xUnit.js.Stubs.GetList(null);
            });

            Assert.Equal(expected,actual);
        }

        [Fact]
        function ThrowsIfSourceListIsUndefined(){
            var expected="xUnit.js.Stubs.GetList: 'sourceList' must be a valid Array.";

            var actual=Record.Exception(function(){
                xUnit.js.Stubs.GetList(undefined);
            });

            Assert.Equal(expected,actual);
        }

        [Fact]
        function ThrowsIfSourceListIsBoolean(){
            var expected="xUnit.js.Stubs.GetList: 'sourceList' must be a valid Array.";

            var actual=Record.Exception(function(){
                xUnit.js.Stubs.GetList(true);
            });

            Assert.Equal(expected,actual);
        }

        [Fact]
        function ThrowsIfSourceListIsError(){
            var expected="xUnit.js.Stubs.GetList: 'sourceList' must be a valid Array.";

            var actual=Record.Exception(function(){
                xUnit.js.Stubs.GetList(new Error());
            });

            Assert.Equal(expected,actual);
        }

        [Fact]
        function ThrowsIfSourceListIsFunction(){
            var expected="xUnit.js.Stubs.GetList: 'sourceList' must be a valid Array.";

            var actual=Record.Exception(function(){
                xUnit.js.Stubs.GetList(function(){});
            });

            Assert.Equal(expected,actual);
        }

        [Fact]
        function ThrowsIfSourceListIsNumber(){
            var expected="xUnit.js.Stubs.GetList: 'sourceList' must be a valid Array.";

            var actual=Record.Exception(function(){
                xUnit.js.Stubs.GetList(1);
            });

            Assert.Equal(expected,actual);
        }

        [Fact]
        function ThrowsIfSourceListIsObject(){
            var expected="xUnit.js.Stubs.GetList: 'sourceList' must be a valid Array.";

            var actual=Record.Exception(function(){
                xUnit.js.Stubs.GetList({});
            });

            Assert.Equal(expected,actual);
        }

        [Fact]
        function ThrowsIfSourceListIsString(){
            var expected="xUnit.js.Stubs.GetList: 'sourceList' must be a valid Array.";

            var actual=Record.Exception(function(){
                xUnit.js.Stubs.GetList("string");
            });

            Assert.Equal(expected,actual);
        }

        [Fact]
        function ReturnsEmptyArray(){
            var expected=[];

            var actual=xUnit.js.Stubs.GetList([]);
        
            Assert.Equal(expected,actual);
        }

        [Fact]
        function GetsStubObjectForArrayEntry(){
            var targetGetObject=xUnit.js.Stubs.GetObject;
            xUnit.js.Stubs.GetObject=function(){
                actual=true;
            }
            var actual=false;

            xUnit.js.Stubs.GetList(["value"]);
            xUnit.js.Stubs.GetObject=targetGetObject;

            Assert.True(actual);
        }

        [Fact]
        function PassesMethodsToStubObject(){
            var targetGetObject=xUnit.js.Stubs.GetObject;
            xUnit.js.Stubs.GetObject=function(targetMethods){
                actual=targetMethods;
            }
            var expected={method:{}};
            var actual=null;

            xUnit.js.Stubs.GetList(["value"],expected);
            xUnit.js.Stubs.GetObject=targetGetObject;

            Assert.Equal(expected,actual);
        }

        [Fact]
        function PassesPropertiesToStubObject(){
            var targetGetObject=xUnit.js.Stubs.GetObject;
            xUnit.js.Stubs.GetObject=function(methods,targetProperties){
                actual=targetProperties;
            }
            var expected={property:"property"};
            var actual=null;

            xUnit.js.Stubs.GetList(["value"],null,expected);
            xUnit.js.Stubs.GetObject=targetGetObject;

            Assert.Equal(expected,actual);
        }

        [Fact]
        function AddsStubObjectToResultList(){
            var targetGetObject=xUnit.js.Stubs.GetObject;
            xUnit.js.Stubs.GetObject=function(){
                return expected;
            }
            var expected="expected";

            var actual=xUnit.js.Stubs.GetList(["value"])[0];
            xUnit.js.Stubs.GetObject=targetGetObject;

            Assert.Equal(expected,actual);
        }

        [Fact]
        function SetsSourceValueOnStub(){
            var expected="expected";

            var actual=xUnit.js.Stubs.GetList([expected])[0].Source_Value;
        
            Assert.Equal(expected,actual);
        }
    }

    [Fixture]
    function GetMethod(){
        [Fact]
        function ReturnsFunction(){
            var actual=xUnit.js.Stubs.GetMethod();

            Assert.Type(Function,actual);
        }

        [Fact]
        function SetsEmptyCallsArrayOnStubMethod(){
            var expected=[];

            var actual=xUnit.js.Stubs.GetMethod().Calls;

            Assert.Equal(expected,actual);        
        }

        [Fact]
        function CallingStubInvokesReturnValueIfMethod(){
            var actual=false;

            xUnit.js.Stubs.GetMethod(function(){
                actual=true;
            })();

            Assert.True(actual);        
        }

        [Fact]
        function CallingStubReturnsMethodReturnValue(){
            var expected="expected";

            var actual=xUnit.js.Stubs.GetMethod(function(){
                return expected;
            })();

            Assert.Equal(expected,actual);        
        }

        [Fact]
        function CallingStubReturnsObjectReturnValue(){
            var expected="expected";

            var actual=xUnit.js.Stubs.GetMethod(expected)();

            Assert.Equal(expected,actual);        
        }

        [Fact]
        function CallingStubStoresArgumentsInCalls(){
            var expected="expected";
            var target=xUnit.js.Stubs.GetMethod("param1",undefined);

            target(expected);
            var actual=target.Calls[0].Arguments.param1;

            Assert.Equal(expected,actual);        
        }

        [Fact]
        function CallingStubStoresReturnValueInCalls(){
            var expected="expected";
            var target=xUnit.js.Stubs.GetMethod("param1",expected);

            target(null);
            var actual=target.Calls[0].ReturnValue;

            Assert.Equal(expected,actual);        
        }

        [Fact]
        function MultipleCallsStoreArgumentsInCalls(){
            var expected="expected";
            var target=xUnit.js.Stubs.GetMethod("param1",undefined);

            target("unexpected");
            target(expected);
            var actual=target.Calls[1].Arguments.param1;

            Assert.Equal(expected,actual);        
        }

        [Fact]
        function MultipleCallsStoreReturnValuesInCalls(){
            var expected="expected";
            var target=xUnit.js.Stubs.GetMethod("param1",undefined);

            target(null);
            target.ReturnValue=expected;
            target(null);
            var actual=target.Calls[1].ReturnValue;

            Assert.Equal(expected,actual);        
        }
    }

    [Fixture]
    function GetObject(){
        [Fact]
        function ImpersonatesSpecifiedType(){
            if(!Object.create){
                return "Object.create required to impersonate types.";
            }
            var expected=function ctor(){};

            var target=xUnit.js.Stubs.GetObject(null,null,expected);
            var actual=(target instanceof expected);

            Assert.True(actual);
        }
        
        [Fact]
        function CallsStubGetMethod(){
            var targetGetMethod=xUnit.js.Stubs.GetMethod;
            xUnit.js.Stubs.GetMethod=function(){
                actual=true;
            }
            var actual=false;

            xUnit.js.Stubs.GetObject({method:{}});
            xUnit.js.Stubs.GetMethod=targetGetMethod;
        
            Assert.True(actual);
        }

        [Fact]
        function PassesParameterFromNativeMethod(){
            var expected="expected";

            var target=xUnit.js.Stubs.GetObject({method:function(expected){}});
            var actual=target.method.Parameters[0];
        
            Assert.Equal(expected,actual);
        }

        [Fact]
        function SetsNativeMethodToReturnValue(){
            var expected=function(){};
            
            var target=xUnit.js.Stubs.GetObject({method:expected});
            var actual=target.method.ReturnValue;
        
            Assert.Equal(expected,actual);
        }

        [Fact]
        function SetsNativeMethodToReturnValueWhenParametersPresent(){
            var expected=function(param1,param2){};

            var target=xUnit.js.Stubs.GetObject({method:expected});
            var actual=target.method.ReturnValue;
        
            Assert.Equal(expected,actual);
        }

        [Fact]
        function PassesParameterFromMethodObject(){
            var targetGetMethod=xUnit.js.Stubs.GetMethod;
            xUnit.js.Stubs.GetMethod=function(targetParameter){
                actual=targetParameter;
            }
            var expected="expected";
            var actual=null;

            xUnit.js.Stubs.GetObject({method:{parameters:[expected]}});
            xUnit.js.Stubs.GetMethod=targetGetMethod;
        
            Assert.Equal(expected,actual);
        }

        [Fact]
        function SetsReturnValueFromMethodObject(){
            var targetGetMethod=xUnit.js.Stubs.GetMethod;
            xUnit.js.Stubs.GetMethod=function(targetReturnValue){
                actual=targetReturnValue;
            }
            var expected="expected";
            var actual=null;

            xUnit.js.Stubs.GetObject({method:{returnValue:expected}});
            xUnit.js.Stubs.GetMethod=targetGetMethod;
        
            Assert.Equal(expected,actual);
        }

        [Fact]
        function SetsReturnValueFromMethodObjectWhenParametersArePresent(){
            var targetGetMethod=xUnit.js.Stubs.GetMethod;
            xUnit.js.Stubs.GetMethod=function(parameterOne,parameterTwo,targetReturnValue){
                actual=targetReturnValue;
            }
            var expected="expected";
            var actual=null;

            xUnit.js.Stubs.GetObject({method:{parameters:["param1","param2"],returnValue:expected}});
            xUnit.js.Stubs.GetMethod=targetGetMethod;
        
            Assert.Equal(expected,actual);
        }

        [Fact]
        function SetsMethodOnStubObject(){
            var targetGetMethod=xUnit.js.Stubs.GetMethod;
            xUnit.js.Stubs.GetMethod=function(parameterOne,parameterTwo,targetReturnValue){
                return expected
            }
            var targetMethods={};
            var targetMethod="method";
            targetMethods[targetMethod]={};
            var expected="expected";

            var actual=xUnit.js.Stubs.GetObject(targetMethods)[targetMethod];
            xUnit.js.Stubs.GetMethod=targetGetMethod;
        
            Assert.Equal(expected,actual);
        }

        [Fact]
        function CopiesPropertiesToStubObject(){
            var expected={one:1,two:"two",three:function(){}};
            
            var actual=xUnit.js.Stubs.GetObject(null,expected);

            Assert.Equal(expected,actual);
        }
    }
}